﻿//*************************************************************************************************
// XPathValidationRule.cs
// Owner: Mahipal Kante
//
// This web test plugin validates a Web Service response using XPath expression.
// The Web Service response can be plain XML or 'application/soap+msbin1'
// (binary - used by Silverlight application with WCF RIA) or JSON
//
// Copyright(c) Microsoft Corporation, 2010
//*************************************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Microsoft.VisualStudio.TestTools.WebTesting;
using System.Xml.XPath;
using System.IO;
using System.Xml;

namespace WebTest.WebService.Plugin.Runtime
{
    [DisplayName("XPathValidationRule")]
    [Description("Validates response using XPath expression")]
    public class XPathValidationRule : ValidationRule
    {
        // The name of the desired input field
        private string xPathValue;
        [DisplayName("XPathToSearch")]
        [Description("XPath expression to evaluate")]
        public string XPathToSearch
        {
            get { return xPathValue; }
            set { xPathValue = value; }
        }

        private int indexValue = -1;
        [Description("Indicates which occurrence of the XPath result to validate. This is a zero based index. -1 indicates try and match against all of them.")]
        public int Index
        {
            get { return indexValue; }
            set { indexValue = value; }
        }

        private string expectedValue = string.Empty;
        [DisplayName("ExpectedValue")]
        [Description("The Expected result of XPath evaluation")]
        public string ExpectedValue
        {
            get { return expectedValue; }
            set { expectedValue = value; }
        }

        private bool ignoreCase = true;
        [DisplayName("IgnoreCase")]
        [Description("Ignores case when comparing the result of XPath with the expected value")]
        public bool IgnoreCase
        {
            get { return ignoreCase; }
            set { ignoreCase = value; }
        }

        /// <summary>
        /// The Validation method.  The parameter e contains the Web test context.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public override void Validate(object sender, ValidationEventArgs e)
        {
            try
            {
                ContentHandler contentHandler = ContentHandlerFactory.GetHandler(e.Response.ContentType);
                if (contentHandler == null)
                {
                    return;
                }

                if (contentHandler.IsBinary)
                {
                    contentHandler.MessageBytes = e.Response.BodyBytes;
                }
                else
                {
                    contentHandler.MessageString = e.Response.BodyString;
                }

                XPathNodeIterator iterator = contentHandler.EvaluateXPath(XPathToSearch);
                int i = 0;
                while (iterator.MoveNext())
                {
                    XPathNavigator nav2 = iterator.Current.Clone();
                    if ((i == -1) || (i == Index))
                    {
                        string value;
                        if (nav2.NodeType.Equals(XPathNodeType.Element))
                        {
                            value = nav2.InnerXml;
                        }
                        else
                        {
                            value = nav2.Value;
                        }


                        if (ignoreCase)
                        {
                            e.IsValid = ExpectedValue.Equals(value, StringComparison.OrdinalIgnoreCase);
                        }
                        else
                        {
                            e.IsValid = ExpectedValue.Equals(value, StringComparison.Ordinal);
                        }

                        if (i == Index || e.IsValid)
                        {
                            return;
                        }
                    }
                    i++;
                }
            }
            catch (Exception ex)
            {
                e.Message = ex.Message;
            }

            e.IsValid = false;
            return;
        }
    }
}
